/*
 *所有关于Aps_ScheduleTask类的业务代码应在此处编写
*可使用repository.调用常用方法，获取EF/Dapper等信息
*如果需要事务请使用repository.DbContextBeginTransaction
*也可使用DBServerProvider.手动获取数据库相关信息
*用户信息、权限、角色等使用UserContext.Current操作
*Aps_ScheduleTaskService对增、删、改查、导入、导出、审核业务代码扩展参照ServiceFunFilter
*/
using DGZImp.Core.BaseProvider;
using DGZImp.Core.Extensions.AutofacManager;
using DGZImp.ApsProject.DomainModels;
using System.Linq;
using DGZImp.Core.Utilities;
using System.Linq.Expressions;
using DGZImp.Core.Extensions;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using DGZImp.ApsProject.IRepositories;
using DGZImp.ApsProject.Dtos;
using DGZImp.Core.Exceptions;
using DGZImp.Core.EFDbContext;
using DGZImp.Core.ManageUser;
using SqlSugar;
using DGZImp.Core.DbSqlSugar;
using System.Reflection.Emit;
using DGZImp.BasProject.DomainModels;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Drawing;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace DGZImp.ApsProject.Services
{
    public partial class Aps_ScheduleTaskService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IAps_ScheduleTaskRepository _repository;//访问数据库
        public ISqlSugarClient Db = AutofacContainerModule.GetService<ServiceDbContext>()?.SqlSugarClient;
        public UserInfo userInfo = UserContext.Current.UserInfo;

        [ActivatorUtilitiesConstructor]
        public Aps_ScheduleTaskService(
            IAps_ScheduleTaskRepository dbRepository,
            IHttpContextAccessor httpContextAccessor
            )
        : base(dbRepository)
        {
            _httpContextAccessor = httpContextAccessor;
            _repository = dbRepository;
            //多租户会用到这init代码，其他情况可以不用
            //base.Init(dbRepository);
        }

        /// <summary>
        /// 获取甘特图数据
        /// </summary>
        ///// <returns></returns>
        public async Task<ReqGanttTable> GetGanttChartData(ReqGanttChartData req)
        {
            if (req.ScheduleVersionId == 0)
                throw new AppException("请选择排程版本");
            if (req.GroupIds.Count() == 0)
                throw new AppException("无工序信息,请选择工序");

            var res = new ReqGanttTable();

            // 获取排程任务信息
            var ScheduInfo = await Db.Set<Aps_ScheduleTask>()
                 .LeftJoin<Bas_GroupConfig>((x, b) => x.GroupId == b.GroupId && b.IsValid == 1)
                 .Where(x => x.ScheduleVersionId == req.ScheduleVersionId)
                 .WhereIF(req.GroupIds.Count() > 0, x => req.GroupIds.Contains(x.GroupId))
                 .GroupBy(x => new { x.GroupId, x.MoCode, x.ProductsCode })
                 .Select((x, b) => new ResScheduInfo
                 {
                     ScheduleTaskId = x.ScheduleTaskId,
                     StartTime = SqlFunc.AggregateMin(x.WorkingStartTime),
                     EndTime = SqlFunc.AggregateMax(x.WorkingEndTime),
                     GroupId = x.GroupId,
                     GroupCode = b.GroupCode,
                     GroupName = b.GroupName,
                     GroupCodeName = b.GroupCode + " " + b.GroupName,
                     MoCode = x.MoCode,
                     Qty = SqlFunc.AggregateSum(x.Qty),
                     ProductsCode = x.ProductsCode,
                     DeadLine = x.DeadLine,
                     Weight = x.Weight,
                     UPH = SqlFunc.AggregateSum(x.UPH),
                     PreparationMinutes = SqlFunc.AggregateSum(x.PreparationMinutes),
                     BeforeMinutes = SqlFunc.AggregateSum(x.BeforeMinutes),
                     AfterMinutes = SqlFunc.AggregateSum(x.AfterMinutes),
                     SalesOrderId = x.SalesOrderId,
                     SalesMaterialId = x.SalesMaterialId,

                 })
            .ToListAsync();


            // 获取排程任务日期信息
            var list = Db.Set<Aps_ScheduleTaskDate>()
                .LeftJoin<Bas_Machine>((a, b) => a.MachineId == b.MachineId && b.IsValid == 1)
                .LeftJoin<Bas_GroupConfig>((a, b, c) => a.GroupId == c.GroupId && c.IsValid == 1)
                .LeftJoin<Aps_ScheduleTask>((a, b, c, d) => a.ScheduleTaskId == d.ScheduleTaskId)
                .Where((a, b, c) => a.ScheduleVersionId == req.ScheduleVersionId)
                .WhereIF(req.GroupIds.Count() > 0, a => req.GroupIds.Contains(a.GroupId))
                .Select((a, b, c, d) => new ScheduleList
                {
                    ScheduleTaskDateId = a.ScheduleTaskDateId.SelectAll(),
                    UPH = d.UPH,
                    GroupId = a.GroupId,
                    ScheduleTaskId = a.ScheduleTaskId,
                    MachineCode = b.MachineCode,
                    MachineName = b.MachineName,
                    GroupCode = c.GroupCode,
                    GroupName = c.GroupName,
                    PreparationMinutes = d.PreparationMinutes,
                    BeforeMinutes = d.BeforeMinutes,
                    AfterMinutes = d.AfterMinutes,
                })
                .ToList();


            var data = list.GroupBy(a => new { a.GroupId, a.MoCode, a.WorkDate, a.ProductsCode, a.ScheduleTaskId })
              .Select(x => new ResScheduDate
              {
                  GroupId = x.Key.GroupId,
                  MoCode = x.Key.MoCode,
                  WorkDate = x.Key.WorkDate,
                  ProductsCode = x.Key.ProductsCode,
                  Qty = x.Sum(a => a.Qty),
                  ScheduleTaskId = x.Key.ScheduleTaskId,
                  Details = x.Where(a => a.WorkDate == x.Key.WorkDate && a.MoCode == x.Key.MoCode && a.GroupId == x.Key.GroupId).ToList()
              }).ToList();



            DateTime? beginTime = DateTime.Now.Date;
            DateTime? endTime = DateTime.Now.AddDays(30).Date;
            if (ScheduInfo.Count() > 0)
            {
                //beginTime = list.Min(a => a.WorkDate);

                if (list.Max(a => a.WorkDate) > endTime)
                    endTime = list.Max(a => a.WorkDate);
            }

            //工厂行事历
            var calendar = Db.Set<Aps_PlantCalendar>()
                .LeftJoin<Aps_Shift>((a, b) => a.ShiftId == b.ShiftId)
                .Where((a, b) => a.WorkDate >= beginTime && a.WorkDate <= endTime)
                .Where((a, b) => a.DateType == "W")
                .OrderBy(a => a.WorkDate)
                .Select((a, b) => new ResLeanApsLineCalendarInfo
                {
                    PlantCalendarId = a.PlantCalendarId.SelectAll(),
                    ShiftCode = b.ShiftCode,
                    ShiftName = b.ShiftName
                }).ToList();



            // 行事历休息日
            var restDays = Db.Set<Aps_PlantCalendar>()
                 .Where(x => x.DateType == "R")
                 .Where(x => x.WorkDate >= beginTime && x.WorkDate <= endTime)
                 .ToList(x => x.WorkDate);



            res.task = ScheduInfo;
            res.taskDate = data;
            res.calendar = calendar;
            res.restDays = restDays;
            res.MinDate = list.Min(a => a.WorkDate);
            res.MaxDate = list.Max(a => a.WorkDate);
            return res;
        }

        /// <summary>
        /// 获取甘特图设备数据
        /// </summary>
        ///// <returns></returns>
        public async Task<ReqGanttTableMachine> GetGanttChartDataByMachine(ReqGanttChartDataByMachine req)
        {
            if (req.ScheduleVersionId == 0)
                throw new AppException("请选择排程版本");
            if (req.MachineIds.Count() == 0)
                throw new AppException("无设备信息,请选择设备");

            var curMachineIds = req.MachineIds;

            if (req.PlantId != 0 && req.PlantId != null)
            {
                var MachineIds = Db.Set<Bas_Machine>().Where(a => a.PlantId == req.PlantId).Select(a => a.MachineId).ToList();
                curMachineIds = MachineIds;
            }

            var res = new ReqGanttTableMachine();

            // 获取排程任务信息
            var ScheduInfo = await Db.Set<Aps_ScheduleTask>()
                 .LeftJoin<Bas_GroupConfig>((x, b) => x.GroupId == b.GroupId && b.IsValid == 1)
                 .LeftJoin<Bas_Machine>((x, b, c) => x.MachineId == c.MachineId && c.IsValid == 1)
                 .Where(x => x.ScheduleVersionId == req.ScheduleVersionId)
                 .WhereIF(curMachineIds.Count() > 0, x => curMachineIds.Contains((long)x.MachineId))
                 .Select((x, b, c) => new ResScheduInfo
                 {

                     ScheduleTaskId = x.ScheduleTaskId.SelectAll(),
                     StartTime = x.WorkingStartTime,
                     EndTime = x.WorkingEndTime,
                     GroupId = x.MachineId,
                     GroupCode = c.MachineCode,
                     GroupName = c.MachineName,
                     GroupCodeName = c.MachineCode + " " + c.MachineName,
                     MoCode = x.MoCode,
                     PreMoCode = x.PreMoCode,
                     Qty = x.Qty,
                     ProductsCode = x.ProductsCode,
                     DeadLine = x.DeadLine,
                     Weight = x.Weight,
                     UPH = x.UPH,
                     PreparationMinutes = x.PreparationMinutes,
                     BeforeMinutes = x.BeforeMinutes,
                     AfterMinutes = x.AfterMinutes,
                     SalesOrderId = x.SalesOrderId,
                     SalesMaterialId = x.SalesMaterialId,

                 })
            .ToListAsync();

            foreach (var item in ScheduInfo)
            {
                if (string.IsNullOrEmpty(item.PreMoCode))
                {
                    item.PreMoCode = "无";
                }
            }


            // 获取排程任务日期信息
            var list = Db.Set<Aps_ScheduleTaskDate>()
                .LeftJoin<Bas_Machine>((a, b) => a.MachineId == b.MachineId && b.IsValid == 1)
                .LeftJoin<Bas_GroupConfig>((a, b, c) => a.GroupId == c.GroupId && c.IsValid == 1)
                .LeftJoin<Aps_ScheduleTask>((a, b, c, d) => a.ScheduleTaskId == d.ScheduleTaskId)
                .Where((a, b, c) => a.ScheduleVersionId == req.ScheduleVersionId)
                .WhereIF(curMachineIds.Count() > 0, a => curMachineIds.Contains((long)a.MachineId))
                .Select((a, b, c, d) => new ScheduleList
                {
                    ScheduleTaskDateId = a.ScheduleTaskDateId.SelectAll(),
                    UPH = d.UPH,
                    GroupId = a.GroupId,
                    ScheduleTaskId = a.ScheduleTaskId,
                    MachineCode = b.MachineCode, // 此处未新建dto
                    MachineName = b.MachineName,
                    GroupCode = c.GroupCode,
                    GroupName = c.GroupName,
                    PreparationMinutes = d.PreparationMinutes,
                    BeforeMinutes = d.BeforeMinutes,
                    AfterMinutes = d.AfterMinutes,
                })
                .ToList();



            var data = list.GroupBy(a => new { a.MachineId, a.MoCode, a.WorkDate, a.ProductsCode, a.ScheduleTaskId })
              .Select(x => new ResScheduDate
              {
                  GroupId = x.Key.MachineId,
                  MoCode = x.Key.MoCode,
                  WorkDate = x.Key.WorkDate,
                  ProductsCode = x.Key.ProductsCode,
                  Qty = x.Sum(a => a.Qty),
                  ScheduleTaskId = x.Key.ScheduleTaskId,
                  Details = x.Where(a => a.WorkDate == x.Key.WorkDate && a.MoCode == x.Key.MoCode && a.MachineId == x.Key.MachineId).ToList()
              }).ToList();


            var minDate = list.Min(a => a.WorkDate);
            var maxDate = list.Max(a => a.WorkDate);

            DateTime? beginTime = DateTime.Now.Date.AddDays(req.agoDay); // 看几天前的排程数据


            if (beginTime > minDate)
            {
                beginTime = minDate;
            }

            DateTime? endTime = beginTime.Value.AddDays(30).Date;

            if (endTime < maxDate)
            {
                endTime = maxDate;
            }

            if (ScheduInfo.Count() > 0)
            {
                //beginTime = list.Min(a => a.WorkDate);

                if (list.Max(a => a.WorkDate) > endTime)
                    endTime = list.Max(a => a.WorkDate);
            }


            var calendar = Db.Set<Aps_MachineShift>()
                .LeftJoin<Bas_Machine>((a, b) => a.MachineId == b.MachineId && b.IsValid == 1)
                .LeftJoin<Aps_Shift>((a, b, c) => a.ShiftId == c.ShiftId && c.IsValid == 1)
                .Where((a, b) => a.WorkDate >= beginTime && a.WorkDate <= endTime)
                .Where((a, b, c) => a.ClockInType != 2 && b.Level != null && c.ShiftCode != null)
                .WhereIF(curMachineIds.Count() > 0, a => curMachineIds.Contains((long)a.MachineId))
                .GroupBy((a, b, c) => new { a.MachineId, a.WorkDate, c.ShiftType })
                .OrderBy(a => a.WorkDate)
                .Select((a, b, c) => new MachineShift
                {
                    MachineShiftId = SqlFunc.AggregateMax(a.MachineShiftId),
                    row_id = SqlFunc.AggregateMax(b.MachineName),
                    Hours = SqlFunc.AggregateSum(a.Hours),
                    WorkDate = a.WorkDate,
                    StartTime = SqlFunc.AggregateMin(a.StartTime),
                    EndTime = SqlFunc.AggregateMin(a.EndTime),
                    ShiftCode = SqlFunc.AggregateMax(c.ShiftCode),
                    ShiftName = SqlFunc.AggregateMax(c.ShiftName),
                    MachineId = a.MachineId

                }).ToList();




            // 行事历休息日
            var restDays = Db.Set<Aps_PlantCalendar>()
                 .Where(x => x.DateType == "R")
                 .Where(x => x.WorkDate >= beginTime && x.WorkDate <= endTime)
                 .ToList(x => x.WorkDate);



            res.task = ScheduInfo;
            res.taskDate = data;
            res.calendar = calendar;
            res.restDays = restDays;
            res.MinDate = list.Min(a => a.WorkDate);
            res.MaxDate = list.Max(a => a.WorkDate);
            return res;
        }

        // 修改出货日
        //public async Task<string> UpdateDeliveryDate(ReqUpdateDeliveryDate req)
        //{

        //}

        public async Task<PageGridData<ApsOrderInfo>> GetApsSalesOrderList(ReqGetSalerOrder req)
        {
            var size = req.size == 0 ? 99999 : req.size;
            RefAsync<int> total = 0;
            PageGridData<ApsOrderInfo> pageGridData = new PageGridData<ApsOrderInfo>();

            var list = await Db.Set<Aps_SalesOrder>()
                            .LeftJoin<Bas_Material>((x, b) => x.MaterialId == b.MaterialId)
                            .Where((x, b) => req.ids.Contains(x.SalesOrderId))
                            .WhereIF(!string.IsNullOrEmpty(req.query), (x, b) => x.OrderNo.Contains(req.query) || b.MaterialName.Contains(req.query))
                            .Select((x, b) => new ApsOrderInfo
                            {
                                SalesOrderId = x.SalesOrderId.SelectAll(),
                                MaterialtCode = b.MaterialCode,
                                MaterialtName = b.MaterialName
                            })
                            .OrderBy(x => x.OrderPriority)
                            .ToPageListAsync(req.page, size, total);
            pageGridData.rows = list;
            pageGridData.total = total;
            return pageGridData;
        }




        /// 下发任务
        public async Task<string> SendTask(ReqOrderTaskData item)
        {
            var ids = item.OrderIds;
            var ScheduleVersionId = item.ScheduleVersionId;
            if (ids.Count() == 0 || ScheduleVersionId == 0)
            {
                throw new AppException("请选择订单信息以及排程版本");
            }

            // 获取所有的排产数据
            var AllTaskData = await Db.Set<Aps_ScheduleTask>().Where(x => x.ScheduleVersionId == ScheduleVersionId).ToListAsync();




            var mainList = AllTaskData
                .Where(x => ids.Contains(x.SalesOrderId))
                .Select(x => new Aps_DistributedTask
                {
                    ScheduleTaskId = x.ScheduleTaskId,
                    ScheduleVersionId = x.ScheduleVersionId,
                    MachineId = x.MachineId,
                    GroupId = x.GroupId,
                    MoCode = x.MoCode,
                    ProductsCode = x.ProductsCode,
                    UPH = x.UPH,
                    OutputCircle = x.OutputCircle,
                    PreparationMinutes = x.PreparationMinutes,
                    BeforeMinutes = x.BeforeMinutes,
                    AfterMinutes = x.AfterMinutes,
                    Weight = x.Weight,
                    DeadLine = x.DeadLine,
                    Seq = x.Seq,
                    IsNew = x.IsNew,
                    IsFinish = x.IsFinish,
                    FinishedQty = x.FinishedQty,
                    FinishStatus = x.FinishStatus,
                    FinishedWeight = x.FinishedWeight,
                    Status = 0,
                    Qty = x.Qty,
                    PreMoCode = x.PreMoCode,
                    SalesOrderId = x.SalesOrderId,
                    StartTime = x.WorkingStartTime,
                    EndTime = x.WorkingEndTime,
                    StepSequence = x.GroupSeq,
                    RouteNameId = x.RouteNameId,

                })
                .ToList();

            var ScheduleTaskIds = mainList.Select(x => x.ScheduleTaskId).ToList();



            var detailList = await Db.Set<Aps_ScheduleTaskDate>()
                .Where(x => ScheduleTaskIds.Contains(x.ScheduleTaskId))
                .Where(x => x.ScheduleVersionId == ScheduleVersionId)
                .Select(x => new Aps_DistributedTaskDate
                {
                    ScheduleVersionId = x.ScheduleVersionId,
                    ScheduleTaskId = x.ScheduleTaskId,
                    MachineId = x.MachineId,
                    GroupId = x.GroupId,
                    WorkDate = x.WorkDate,
                    MoCode = x.MoCode,
                    ProductsCode = x.ProductsCode,
                    ShiftId = x.ShiftId,
                    ShiftType = x.ShiftType,
                    StartTime = x.StartTime,
                    EndTime = x.EndTime,
                    Hours = x.Hours,
                    Qty = x.Qty,
                    Weight = x.Weight,
                    Status = 0,
                    FinishedQty = 0,
                    FinishedWeight = 0

                }).ToListAsync();

            var mos = mainList.Select(x => x.MoCode).ToList();


            var taskMainMo = await Db.Set<Aps_DistributedTask>()
                            .Where(x => mos.Contains(x.MoCode) && (x.Status == 0 || x.Status == 3))
                            .Select(x => x.MoCode)
                            .ToListAsync();

            var taskMainMoDoing = await Db.Set<Aps_DistributedTask>()
                                .Where(x => mos.Contains(x.MoCode) && (x.Status == 1 || x.Status == 2))
                                .ToListAsync();


            var taskDetailMainMo = await Db.Set<Aps_DistributedTaskDate>()
                            .Where(x => mos.Contains(x.MoCode) && (x.Status == 0 || x.Status == 3))
                            .Select(x => x.MoCode)
                            .ToListAsync();


            var moDoing = taskMainMoDoing.Select(x => x.MoCode).ToList();


            //事务处理 先加锁
            bool inTrans = _repository.SqlSugarClient.Ado.Transaction != null;
            if (!inTrans) _repository.SqlSugarClient.Ado.BeginTran();

            try
            {

                if (taskMainMo.Count > 0)
                {

                    await Db.DoUpdateAsync<Aps_DistributedTask>(new { IsValid = 0 }, x => taskMainMo.Contains(x.MoCode));

                }
                if (taskDetailMainMo.Count > 0)
                {
                    await Db.DoUpdateAsync<Aps_DistributedTaskDate>(new { IsValid = 0 }, x => taskDetailMainMo.Contains(x.MoCode));

                }
                // 插入任务主表以及明细表
                if (mainList.Count > 0)
                {
                    var list = mainList.Where(a => !moDoing.Contains(a.MoCode)).ToList();
                    await _repository.DbContext.DoInsertAsync(list);
                }
                if (detailList.Count > 0)
                {
                    await _repository.DbContext.DoInsertAsync(detailList);
                }
                if (!inTrans) _repository.SqlSugarClient.Ado.CommitTran();

                if (taskMainMoDoing.Count > 0)
                {
                    return $"派发成功，但以下工单正在执行中或已完成：{string.Join(",", moDoing)}";
                }

                return "下发成功";
            }
            catch (Exception e)
            {
                if (!inTrans) _repository.SqlSugarClient.Ado.RollbackTran();
                throw new AppException("操作失败：" + e.Message);
            }

        }


    }
}
